import type {
	WL_IDbAudioData,
	WL_IDbFileData,
	WL_IDbLocationInfo,
	WL_IDbLocationShared,
	WL_IDbMsgData,
	WL_IDbPttData,
	WL_IDbServiceSessionInfo,
	WL_IDbSession
} from "@/proto/weilapb_external_data";
import {
	WL_IDbMsgDataStatus,
	WL_IDbMsgDataType,
	WL_IDbSessionStatus,
	WL_IDbSessionType
} from "@/proto/weilapb_external_data";

import type {WL_CoreInterface,} from "@/core/weila_datas"
import {WL_ExtEventID} from "@/core/weila_datas";
import {WL} from "@/proto/weilapb";
import {Weila_MemDB} from "@/mem_store/weila_db";
import Long from "long";
import {MD5} from "crypto-js";
import {calculateOpusDataFrame, fetchWithTimeout} from "@/core/weila_utils";
import {convertFromMsgDataRaws, convertFromSessionRaw, getMsgDataIdByCombo} from "@/proto/weilapb_utils";
import {WeilaPBSessionWrapper} from "@/proto/weilapb_session_wrapper";
import type {WLBuildMsgRet} from "@/proto/weilapb_wrapper_data";

import debug from "debug";
import {WL_PttCore} from "@/core/weila_pttcore";

const SLog = debug("SessionLog");

export default class WLSessionModule {
	private sessionList: WL_IDbSession[];
	private pttCore: WL_PttCore|undefined;

	constructor(private coreInterface: WL_CoreInterface) {
		this.sessionList = [];
		this.coreInterface.registerPbMsgHandler(WL.Service.ServiceID.SERVICE_SESSION, this.onPbMsgHandler.bind(this));
	}

	public setPttCore(pttCore: WL_PttCore) {
		this.pttCore = pttCore;
	}

	private saveSessionInfo(dBSession: WL_IDbSession) {
		if (dBSession.sessionType == WL_IDbSessionType.SESSION_INDIVIDUAL_TYPE) {
			const userInfo = Weila_MemDB.getInstance().getUser(parseInt(dBSession.sessionId));
			if (userInfo) {
				dBSession.sessionName = userInfo.nick;
				dBSession.sessionAvatar = userInfo.avatar;
				Weila_MemDB.getInstance().putSession(dBSession);
			}
		}else if (dBSession.sessionType == WL_IDbSessionType.SESSION_SERVICE_TYPE) {
			const idNumber = Long.fromValue(dBSession.sessionId);
			const service = Weila_MemDB.getInstance().getService(idNumber.high);
			if (service) {
				dBSession.sessionName = service.name;
				dBSession.sessionAvatar = service.avatar;
				Weila_MemDB.getInstance().putSession(dBSession);
			}
		}else {
			Weila_MemDB.getInstance().putSession(dBSession);
		}
	}

	private async updateSessionByNewMsgData(msgData: WL_IDbMsgData): Promise<void> {
		const index = this.sessionList.findIndex(value => {
			return value.sessionId == msgData.sessionId && value.sessionType == msgData.sessionType;
		});

		if (index == -1) {
			let session: WL_IDbSession = {} as WL_IDbSession
			session.sessionId = msgData.sessionId;
			session.sessionType = msgData.sessionType;
			if (msgData.sessionType == WL_IDbSessionType.SESSION_SERVICE_TYPE) {
				// 如果是之前没有这个session，说明此服务也不再DB中，所以需要从服务器获取服务的信息
				const serviceSession: WL_IDbServiceSessionInfo|undefined =
					await this.coreInterface.executeCoreFunc('weila_getServiceSession', msgData.sessionId);
				if (serviceSession) {
					session.sessionName = serviceSession.service.name;
					session.sessionAvatar = serviceSession.service.avatar;
					session.extra = serviceSession.serviceSession;
				}
			}else {
				session.sessionName = "";
				session.sessionAvatar = "";
			}
			session.lastMsgId = msgData.msgId;
			session.latestUpdate = new Date().getTime() / 1000;
			session.combo_id_type = session.sessionId + "_" + session.sessionType;
			Weila_MemDB.getInstance().putSession(session);
			this.sessionList.push(session);
			//发送有新的会话通知
			this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_NEW_SESSION_OPEN_IND, session);
		}else {
			this.sessionList[index].lastMsgId = msgData.msgId;
			this.sessionList[index].latestUpdate = new Date().getTime() / 1000;
			Weila_MemDB.getInstance().putSession(this.sessionList[index]);
		}
	}

	private async getAudioMsgDataFromTextMsgData(msgData: WL_IDbMsgData): Promise<WL_IDbMsgData> {
		try {
			const weilaToken = Weila_MemDB.getInstance().getLoginToken();
			const loginUser = Weila_MemDB.getInstance().getLoginUserInfo();
			let speakerInfo = '';
			const senderUserInfo = Weila_MemDB.getInstance().getUser(msgData.senderId);

			if (senderUserInfo) {
				speakerInfo = senderUserInfo.nick;
			}else {
				speakerInfo = '未知用户';
			}

			if (msgData.sessionType == WL_IDbSessionType.SESSION_GROUP_TYPE ||
			msgData.sessionType == WL_IDbSessionType.SESSION_CORP_GROUP_TYPE ||
			msgData.sessionType == WL_IDbSessionType.SESSION_TYPE_CORP_GROUP_TMP) {
				// const groupInfo = await WeilaDB.getInstance().getGroup(msgData.sessionId);
				// if (groupInfo) {
				// 	speakerInfo += '在' + groupInfo.name + '里';
				// }

				speakerInfo += '在群里';
			}else if (msgData.sessionType == WL_IDbSessionType.SESSION_SERVICE_TYPE) {
				// const service = await WeilaDB.getInstance().getService(Long.fromValue(msgData.sessionId).high);
				// if (service) {
				// 	speakerInfo += '在' + service.name + '里';
				// }

				speakerInfo += '在服务会话里';
			}
			speakerInfo += '说';

			const data: any = {};
			data['user_id'] = loginUser!.userId;
			data['text'] = speakerInfo + msgData.textData;
			SLog('文字转语音，文字：%s', data['text']);
			data['speed'] = 8;
			data['vol'] = 6;
			data['et'] = (Math.floor(Date.now() / 1000) + 20).toString(10);

			// @ts-ignore
			data['app_id'] = import.meta.env.APP_ID;

			// @ts-ignore
			data['sign'] = MD5(data['et'] + import.meta.env.APP_KEY).toString();

			const response = await fetchWithTimeout('/v1/speech/synthesis/ptt?access-token=' + weilaToken,
				{method: 'POST', body: JSON.stringify(data), headers: {'Content-Type': 'application/json'}});

			if (response.ok) {
				const data = await response.json();
				if (data.errcode == 0) {
					let matchResult = data.data.url.match(/(http|https):\/\/([^\/]+)\/(.+)/i);
					if (matchResult && matchResult.length >= 4) {
						const pttUrl = "/" + matchResult[3];
						const audioData = await fetchWithTimeout(pttUrl).then(value => {
							if (value.ok) {
								return value.arrayBuffer();
							}

							SLog('获取音频数据出错: %o', value.statusText);
							return null;
						}).catch(reason => {
							SLog('获取音频数据失败 %o', reason);
						});

						if (audioData) {
							const audioMsgData = {} as WL_IDbMsgData;
							audioMsgData.sessionId = msgData.sessionId;
							audioMsgData.sessionType = msgData.sessionType;
							audioMsgData.msgId = msgData.msgId;
							audioMsgData.msgType = WL_IDbMsgDataType.WL_DB_MSG_DATA_AUDIO_TYPE;
							audioMsgData.created = msgData.created;
							audioMsgData.senderId = msgData.senderId;
							audioMsgData.audioData = {} as WL_IDbAudioData;
							audioMsgData.audioData.data = new Uint8Array(audioData.slice(10));
							audioMsgData.audioData.frameCount = calculateOpusDataFrame(audioMsgData.audioData.data);
							audioMsgData.combo_id = getMsgDataIdByCombo(audioMsgData, 0);
							return audioMsgData;
						}else {
							return Promise.reject('获取音频数据失败');
						}
					}else {
						return Promise.reject('ptt的地址不正确');
					}
				}else {
					return Promise.reject('获取ptt地址失败:' + data.errmsg);
				}
			}else{
				return Promise.reject(response.statusText);
			}
		}catch (e) {
			return Promise.reject(e);
		}
	}

	private onPbMsgHandler(data: any): void {
		const serverMessage = data as WL.Service.IServiceMessage;
		if (serverMessage.serviceHead!.commandType == WL.Service.CommandType.COMMAND_RESPONSE) {
			switch (serverMessage.serviceHead!.commandId) {
				case WL.Session.SessionCommandId.SESSION_COMMAND_MSGDATA: {
					this.coreInterface.rspPbMsg(serverMessage.serviceHead!.seq!, serverMessage.serviceHead!.resultCode!,
						serverMessage.sessionMessage!.rspMsg);
				}
				break;

				case WL.Session.SessionCommandId.SESSION_COMMAND_GET_SESSION: {
					this.coreInterface.rspPbMsg(serverMessage.serviceHead!.seq!, serverMessage.serviceHead!.resultCode!,
						serverMessage.sessionMessage!.rspGetSession);
				}
				break;

				case WL.Session.SessionCommandId.SESSION_COMMAND_GET_MSG: {
					this.coreInterface.rspPbMsg(serverMessage.serviceHead!.seq!, serverMessage.serviceHead!.resultCode!,
						serverMessage.sessionMessage!.rspGetMsg);
				}
				break;

				case WL.Session.SessionCommandId.SESSION_COMMAND_READ_MSG: {
					this.coreInterface.rspPbMsg(serverMessage.serviceHead!.seq!, serverMessage.serviceHead!.resultCode!,
						serverMessage.sessionMessage!.rspMsgRead);
				}
				break;

				case WL.Session.SessionCommandId.SESSION_COMMAND_REMOVE_SESSION: {
					this.coreInterface.rspPbMsg(serverMessage.serviceHead!.seq!, serverMessage.serviceHead!.resultCode!, true);
				}
				break;
			}
		}else if (serverMessage.serviceHead!.commandType == WL.Service.CommandType.COMMAND_NOTIFY) {
			if (serverMessage.serviceHead!.commandId == WL.Session.SessionCommandId.SESSION_COMMAND_MSGDATA) {
				(async () => {
					const msgDataRaw = serverMessage.sessionMessage!.ntfMsg!.msgData!;
					const loginUserInfo = Weila_MemDB.getInstance().getLoginUserInfo();
					const msgDatas = convertFromMsgDataRaws([msgDataRaw], loginUserInfo!.userId);
					SLog('转换后的消息: %o %o', msgDatas, msgDatas.length);
					if (msgDatas.length) {
						const msgData = msgDatas[0];
						const msgType = msgData.msgType;
						msgData.combo_id = getMsgDataIdByCombo(msgData, 0);
						msgData.preCombo_id = "";
						if (msgData.msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_PTT_TYPE) {
							const {msgData: audioMsgData, newMsg: newMsg} = this.pttCore!.putAudioPacketToStream(msgData);
							if (audioMsgData) {
								await this.updateSessionByNewMsgData(audioMsgData);
								//发送通知消息出去
								if (newMsg) {
									this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_NEW_MSG_RECV_IND, audioMsgData);
								}
							}
						}else if (msgData.msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_TEXT_TYPE) {
							msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_READ;
							try {
								await this.setSessionMsgRead(msgData.sessionId, msgData.sessionType, msgData.msgId);
							}catch (e) {
								SLog("设置消息已读失败", e);
							}
							try {
								const audioData = await this.getAudioMsgDataFromTextMsgData(msgData);
								if (audioData) {
									SLog("文字转语音得到的消息 %o", audioData);
									this.pttCore!.putAudioToStream(audioData, false);
								}
							}catch (e) {
								SLog("获取语音转文字音频失败", e);
							}

						}else if (msgData.msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_AUDIO_TYPE) {
							msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_NEW;
							SLog("得到的音频消息 %o", msgData);
							if (msgData.audioData && msgData.audioData.audioUrl) {
								msgData.audioData = msgData.audioData || {} as WL_IDbAudioData;
								const matches = msgData.audioData.audioUrl!.match(/duration=(.*)$/);
								if (matches) {
									msgData.audioData.frameCount = parseInt(matches[1]) * 50;
								}
							}
							this.pttCore!.putAudioToStream(msgData, true);
						}else {
							try {
								await this.setSessionMsgRead(msgData.sessionId, msgData.sessionType, msgData.msgId);
							}catch (e) {
								SLog("设置消息已读失败", e);
							}
							msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_READ;
						}

						SLog('incoming msgdata: %o', msgData);
						if (msgType != WL_IDbMsgDataType.WL_DB_MSG_DATA_PTT_TYPE) {
							if (msgType != WL_IDbMsgDataType.WL_DB_MSG_DATA_WITHDRAW_TYPE) {
								await this.updateSessionByNewMsgData(msgData);
								//发送通知消息出去
								this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_NEW_MSG_RECV_IND, msgData);
								Weila_MemDB.getInstance().putMsgData(msgData);
							}else {
								const withdrawMsgData = Weila_MemDB.getInstance().getMsgData(msgData.sessionId, msgData.sessionType, msgData.withdrawMsgId!);
								SLog('withdraw msg is: %o', withdrawMsgData);

								if (withdrawMsgData) {
									withdrawMsgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_WITHDRAW;
									//发送通知消息出去
									this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_NEW_MSG_RECV_IND, withdrawMsgData);
									Weila_MemDB.getInstance().putMsgData(withdrawMsgData);
								}
							}
						}
					}
				})();
			}else if (serverMessage.serviceHead!.commandId == WL.Session.SessionCommandId.SESSION_COMMAND_BURST_CONTROL) {
				SLog('收到发言控制消息: %o', serverMessage.sessionMessage!.ntfBurstControl);
			}
		}
	}

	public async getMsgDataFromServer(sessionId: string, sessionType: number, fromMsgId: number, count: number): Promise<WL_IDbMsgData[]> {
		const loginUserInfo = Weila_MemDB.getInstance().getLoginUserInfo();
		SLog("getMsgDataFromServer %o", typeof sessionId);
		const buildResult = WeilaPBSessionWrapper.buildMsgGetMsgReq(
			Long.fromValue(sessionId),
			sessionType,
			fromMsgId,
			count);

		let readMsgId = 0;

		const sessionIdx = this.sessionList.findIndex(value => {
			return value.sessionId == sessionId && value.sessionType == sessionType;
		});

		if (sessionIdx != -1) {
			readMsgId = this.sessionList[sessionIdx].readMsgId;
		}

		if (buildResult.resultCode == 0) {
			try {
				const rspGetMsg = await this.coreInterface.sendPbMsg(buildResult) as WL.Session.IRspGetMsg;
				SLog("从服务器获取: %d 条记录", rspGetMsg.msgList!.length);
				let msgDatas = convertFromMsgDataRaws(rspGetMsg.msgList!, loginUserInfo!.userId);

				msgDatas = msgDatas.filter(value => {
					return value.msgType != WL_IDbMsgDataType.WL_DB_MSG_DATA_WITHDRAW_TYPE;
				});

				msgDatas.forEach(value => {
					value.combo_id = getMsgDataIdByCombo(value, 0);
					if (value.senderId != loginUserInfo!.userId) {
						if (value.msgId > readMsgId) {
							value.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_NEW;
						} else {
							value.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_READ;
						}
					} else {
						value.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_SENT;
					}
				});

				msgDatas.sort((a, b) => {
					return a.created - b.created;
				});

				Weila_MemDB.getInstance().putMsgDatas(msgDatas);
				SLog('从服务器中获取会话消息成功 %o', msgDatas);
				return msgDatas;
			}catch (e) {
				return Promise.reject('读取消息异常:' + e);
			}
		}


		return Promise.reject('创建读取消息异常:' + buildResult.resultCode);
	}

	public async setSessionMsgRead(sessionId: string, sessionType: number, msgId: number): Promise<boolean> {
		const buildResult = WeilaPBSessionWrapper.buildMsgReadReq(Long.fromValue(sessionId), sessionType, msgId);
		if (buildResult.resultCode == 0) {
			const rsp = await this.coreInterface.sendPbMsg(buildResult);
			SLog('设已读的响应结果 %o', rsp);
			return true;
		}

		return Promise.reject('创建读取消息异常:' + buildResult.resultCode);
	}

	private async getSessionFromServer(sessionClass: number): Promise<WL_IDbSession[]> {
		let sessionInfos: WL_IDbSession[] = [];
		const buildResult = WeilaPBSessionWrapper.buildGetSessionReq(Long.fromValue(0), sessionClass);

		if (buildResult.resultCode == 0) {
			let loginUserInfo = Weila_MemDB.getInstance().getLoginUserInfo();
			try {
				let rspMsg = await this.coreInterface.sendPbMsg(buildResult, 30000) as WL.Session.IRspGetSession;

				SLog('initSessions: %o', rspMsg.sessionInfoList);
				if (rspMsg.sessionInfoList!.length) {
					sessionInfos = convertFromSessionRaw(rspMsg.sessionInfoList!, loginUserInfo!.userId);
					SLog('after convert:', sessionInfos);
				}

				return sessionInfos;
			}catch (e) {
				return Promise.reject('创建消息失败:' + e);
			}
		}

		return Promise.reject("创建消息失败[" + buildResult.resultCode + "]");
	}

	public async initSessions(): Promise<boolean> {
		this.sessionList = [];
		try {
			// get personal session first
			let sessionInfos = await this.getSessionFromServer(0);
			sessionInfos.forEach(value => {
				Weila_MemDB.getInstance().putSession(value);
			});

			// get corporation session next
			sessionInfos = await this.getSessionFromServer(1);
			sessionInfos.forEach(value => {
				Weila_MemDB.getInstance().putSession(value);
			});
		}catch (e) {
			SLog("获取会话列表失败:" + e);
		}

		this.sessionList = Weila_MemDB.getInstance().getSessionList();
		SLog('会话列表:', this.sessionList);

		return true;
	}

	public async reSendMsgData(msgData: WL_IDbMsgData): Promise<boolean> {
		let buildResult = null as WLBuildMsgRet|null;
		let seq = Weila_MemDB.getInstance().getMsgSeq();
		let msgType = msgData.msgType;
		let loginUserInfo = Weila_MemDB.getInstance().getLoginUserInfo();
		const lastMsgId = Weila_MemDB.getInstance().getLastMsgId(msgData.sessionId, msgData.sessionType);
		Weila_MemDB.getInstance().delMsgData(msgData.combo_id);
		const index = this.sessionList.findIndex(value => {
			return value.sessionId == msgData.sessionId && value.sessionType == msgData.sessionType;
		});

		msgData.created = Date.now() / 1000;
		msgData.msgId = lastMsgId;
		msgData.combo_id = getMsgDataIdByCombo(msgData, seq++);
		msgData.preCombo_id = msgData.combo_id;
		msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_SENDING;
		Weila_MemDB.getInstance().putMsgSeq(seq);

		if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_TEXT_TYPE) {
			buildResult = WeilaPBSessionWrapper.buildTextSessionMsgReq(Long.fromValue(msgData.sessionId), msgData.sessionType,
				loginUserInfo!.userId, false, msgData.textData as string);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_FILE_TYPE || msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_VIDEO_TYPE) {
			buildResult = WeilaPBSessionWrapper.buildMediaInfoSessionMsgReq(Long.fromValue(msgData.sessionId), msgData.sessionType,
				loginUserInfo!.userId, false, msgData.fileInfo!, msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_FILE_TYPE);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_IMAGE_TYPE) {
			buildResult = WeilaPBSessionWrapper.buildImageSessionMsgReq(Long.fromValue(msgData.sessionId), msgData.sessionType,
				loginUserInfo!.userId, false, msgData.fileInfo!.fileUrl!);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_LOCATION_TYPE) {
			buildResult = WeilaPBSessionWrapper.buildLocationInfoSessionMsgReq(Long.fromValue(msgData.sessionId), msgData.sessionType,
				loginUserInfo!.userId, false, msgData.location!);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_PTT_TYPE) {
			buildResult = WeilaPBSessionWrapper.buildPttSessionMsgReq(Long.fromValue(msgData.sessionId), msgData.sessionType,
				loginUserInfo!.userId, false, msgData.pttData as WL_IDbPttData);
		}

		if (buildResult && buildResult.resultCode == 0) {
			this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_MSG_SENDING_IND, msgData);

			try {
				const rspMsg = await this.coreInterface.sendPbMsg(buildResult!) as WL.Session.IRspMsg;
				Weila_MemDB.getInstance().delMsgData(msgData.combo_id);

				SLog('发送消息成功，返回结果id: %o', rspMsg.msgId);
				msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_SENT;
				msgData.msgId = rspMsg.msgId!;
				msgData.combo_id = getMsgDataIdByCombo(msgData, 0);
				if (index !== -1) {
					this.sessionList[index].lastMsgId = msgData.msgId;
					this.sessionList[index].latestUpdate = new Date().getTime() / 1000;
					Weila_MemDB.getInstance().putSession(this.sessionList[index]);
				}
				return true;
			}catch (e) {
				SLog('发送会话消息失败: %o', e);
				msgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_UNSENT;
				return Promise.reject(e);
			}finally {
				// 不管消息发送成功与否，都存入数据库，并对外发布此消息。
				Weila_MemDB.getInstance().putMsgData(msgData);
				// 通知消息发送
				this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_MSG_SEND_IND, msgData);
			}
		}

		return Promise.reject('创建消息失败:不存在消息类型:' + msgType);

	}

	public async sendMsgData(sessionId: string, sessionType: number,
	                         data: any,
	                         msgType: WL_IDbMsgDataType,
	                         msgData: WL_IDbMsgData|undefined,
							 location?: WL_IDbLocationInfo): Promise<boolean> {
		let buildResult = null as WLBuildMsgRet|null;
		let seq = Weila_MemDB.getInstance().getMsgSeq();
		let loginUserInfo = Weila_MemDB.getInstance().getLoginUserInfo();

		SLog("loginUserInfo %o %o %o", loginUserInfo, Long.fromValue(sessionId).high, Long.fromValue(sessionId).low);
		const index = this.sessionList.findIndex(value => {
			return value.sessionId == sessionId && value.sessionType == sessionType;
		});
		const lastMsgId = Weila_MemDB.getInstance().getLastMsgId(sessionId, sessionType);

		let dbMsgData = {} as WL_IDbMsgData;
		if (msgData) {
			dbMsgData = msgData;
			dbMsgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_SENDING;
		}else {
			dbMsgData.msgType = msgType;
			dbMsgData.sessionId = sessionId;
			dbMsgData.sessionType = sessionType;
			dbMsgData.senderId = loginUserInfo!.userId;
			dbMsgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_SENDING;
			dbMsgData.created = new Date().getTime() / 1000;
			dbMsgData.msgId = lastMsgId;
			dbMsgData.autoReply = 0;
			dbMsgData.combo_id = getMsgDataIdByCombo(dbMsgData, seq++);
			dbMsgData.preCombo_id = dbMsgData.combo_id;
			Weila_MemDB.getInstance().putMsgSeq(seq);
		}

		if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_TEXT_TYPE) {
			dbMsgData.textData = data as string;
			buildResult = WeilaPBSessionWrapper.buildTextSessionMsgReq(Long.fromValue(sessionId), sessionType,
				loginUserInfo!.userId, false, data as string, location);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_FILE_TYPE || msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_VIDEO_TYPE) {
			dbMsgData.fileInfo = data as WL_IDbFileData;
			buildResult = WeilaPBSessionWrapper.buildMediaInfoSessionMsgReq(Long.fromValue(sessionId), sessionType,
				loginUserInfo!.userId, false, data as WL_IDbFileData, msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_FILE_TYPE);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_IMAGE_TYPE) {
			dbMsgData.fileInfo = data as WL_IDbFileData;
			buildResult = WeilaPBSessionWrapper.buildImageSessionMsgReq(Long.fromValue(sessionId), sessionType,
				loginUserInfo!.userId, false, dbMsgData.fileInfo.fileUrl!);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_LOCATION_TYPE) {
			dbMsgData.location = data as WL_IDbLocationShared;
			buildResult = WeilaPBSessionWrapper.buildLocationInfoSessionMsgReq(Long.fromValue(sessionId), sessionType,
				loginUserInfo!.userId, false, data as WL_IDbLocationShared);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_AUDIO_TYPE) {
			dbMsgData.audioData = data as WL_IDbAudioData;
			buildResult = WeilaPBSessionWrapper.buildAudioSessionMsgReq(Long.fromValue(sessionId), sessionType,
				loginUserInfo!.userId, false, data as string);
		}else if (msgType == WL_IDbMsgDataType.WL_DB_MSG_DATA_PTT_TYPE) {
			dbMsgData.pttData = data.pttData;
			dbMsgData.audioData = {} as WL_IDbAudioData;
			dbMsgData.audioData.audioUrl = data.url;
			dbMsgData.audioData.frameCount = dbMsgData.pttData!.frameCount;
			SLog("sending ptt %o %o %o %o", sessionId, sessionType, loginUserInfo!.userId, data.pttData);
			buildResult = WeilaPBSessionWrapper.buildPttSessionMsgReq(Long.fromValue(sessionId), sessionType,
				loginUserInfo!.userId, false, data.pttData as WL_IDbPttData);
		}

		if (buildResult && buildResult.resultCode == 0) {
			this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_MSG_SENDING_IND, dbMsgData);

			try {
				const rspMsg = await this.coreInterface.sendPbMsg(buildResult!) as WL.Session.IRspMsg;
				Weila_MemDB.getInstance().delMsgData(dbMsgData.combo_id);

				SLog('发送消息成功，返回结果id: %o', rspMsg.msgId);
				dbMsgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_SENT;
				dbMsgData.msgId = rspMsg.msgId!;
				dbMsgData.combo_id = getMsgDataIdByCombo(dbMsgData, 0);
				if (index !== -1) {
					this.sessionList[index].lastMsgId = dbMsgData.msgId;
					this.sessionList[index].latestUpdate = new Date().getTime() / 1000;
					SLog("session: %o", this.sessionList);
					Weila_MemDB.getInstance().putSession(this.sessionList[index]);
				}
				return true;
			}catch (e: any) {
				SLog('发送会话消息失败: %o', e);
				dbMsgData.status = WL_IDbMsgDataStatus.WL_DB_MSG_DATA_STATUS_UNSENT;
				dbMsgData.errInfo = e;
				return Promise.reject(e);
			}finally {
				// 不管消息发送成功与否，都存入数据库，并对外发布此消息。
				Weila_MemDB.getInstance().putMsgData(dbMsgData);
				// 通知消息发送
				this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_MSG_SEND_IND, dbMsgData);
			}
		}

		return Promise.reject('创建消息失败:不存在消息类型:' + msgType);
	}

	public async deleteSession(sessionId: string, sessionType: number): Promise<boolean> {
		const buildMsgRet = WeilaPBSessionWrapper.buildRemoveSessionReq(Long.fromValue(sessionId), sessionType);
		if (buildMsgRet.resultCode == 0) {
			try {
				await this.coreInterface.sendPbMsg(buildMsgRet);
			}finally {
				const sessionInfo = Weila_MemDB.getInstance().getSession(sessionId, sessionType);
				const index = this.sessionList.findIndex(value => {
					return value.sessionId == sessionId && value.sessionType == sessionType;
				});
				if (index != -1) {
					this.sessionList.splice(index, 1);
				}
				if (sessionInfo) {
					Weila_MemDB.getInstance().delSession(sessionInfo);
				}
			}

			return true;
		}

		return Promise.reject('创建消息失败:' + buildMsgRet.resultCode);
	}

	public updateSession(session: WL_IDbSession) {
		Weila_MemDB.getInstance().putSession(session);
	}

	public startSession(sessionId: string, sessionType: number, extra?: any): WL_IDbSession {
		const dbSessionInfo = Weila_MemDB.getInstance().getSession(sessionId, sessionType);
		if (dbSessionInfo) {
			return dbSessionInfo;
		}

		const sessionInfo = {} as WL_IDbSession;
		sessionInfo.sessionId = sessionId;
		sessionInfo.sessionType = sessionType;
		sessionInfo.combo_id_type = sessionId + "_" + sessionType;
		sessionInfo.readMsgId = 0;
		sessionInfo.latestUpdate = 0;
		sessionInfo.lastMsgId = 0;
		sessionInfo.sessionName = '';
		sessionInfo.sessionAvatar = "";
		sessionInfo.status = WL_IDbSessionStatus.SESSION_ACTIVATE;
		sessionInfo.extra = extra;

		this.saveSessionInfo(sessionInfo);
		this.sessionList.push(sessionInfo);

		this.coreInterface.sendExtEvent(WL_ExtEventID.WL_EXT_NEW_SESSION_OPEN_IND, sessionInfo);
		return sessionInfo;
	}


	getSessionList(): WL_IDbSession[] {
		return this.sessionList;
	}

	muteSession(sessionId: string, mute: boolean) {
		if (this.pttCore) {
			this.pttCore.muteSession(sessionId, mute);
		}
	}

	muteAllSessions(mute: boolean) {
		if (this.pttCore) {
			const idList = this.sessionList.map(value => {
				return value.sessionId;
			});
			this.pttCore.muteAllSession(idList, mute);
		}
	}

	isAllSessionsMute(): boolean {
		if (this.pttCore) {
			for(let session of this.sessionList) {
				if (!Weila_MemDB.getInstance().isSessionMute(session.sessionId)) {
					return false;
				}
			}

			return true;
		}

		return false;
	}
}
